package sjtu.ChatClient;

import java.io.*;
import java.net.*;
import java.util.TimerTask;
import java.util.Timer;

import genDoc.StopVoiceRequestDocGen;
import genDoc.StoppedVoiceChatDocGen;

import org.jdom.Document;

import command.CommandConstants;
import sjtu.FaceRecognition.*;

import threads.PlayAudioThread;
import threads.ReceiveExpressionThread;
import threads.SendAudioThread;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.view.OrientationEventListener;
import android.widget.ImageView;
import android.hardware.Camera;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.hardware.Camera.PreviewCallback;

public class VoiceChatActivity extends Activity implements SensorEventListener {
	private WakeLock wakeLock;
	private boolean firstTearDown = true;
	private PlayAudioThread playAudioThread;
	private SendAudioThread sendAudioThread;
	private String to;// the other user's user name
	
	private ImgProcessor imgProcessor;
	private OrientationEventListener orientationListener;
	private SensorManager sensorManager;
	private Sensor proximitySensor;
	private PreviewCallback previewCallback = null;
	private boolean chance;
	private ImageView imageResult;
	
	private ReceiveExpressionThread receiveExpressionThread;
	private byte [] expressionBuffer;
	private DatagramSocket expressionSocket;
	private Timer timer;
	
	private void initExpressionTimer(){
		timer = new Timer("ExpressionTimer", false);
		TimerTask task = new TimerTask(){
			public void run(){
				chance = true;
			}
		};
		
		timer.schedule(task, SystemConstants.EXPRESSION_DELAY, SystemConstants.EXPRESSION_DELAY);
	}
	
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_voice_chat);
		
		imageResult = (ImageView) this.findViewById(R.id.image_result);
		imageResult.setBackgroundResource(R.drawable.mic);
		imgProcessor = ImgProcessor.getInstance(this);
		orientationListener = new OrientationEventListener(this) {

    		@Override
    		public void onOrientationChanged(int orientation) {
    			CameraUtil.setRotation(orientation);
    		}
    		
    	};
    	sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
    	proximitySensor = sensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY);
    	
    	
    	CameraUtil.initFrontCameraInstance(VoiceChatActivity.this);
    	CameraUtil.initFrontCameraPreview(VoiceChatActivity.this);
    	setPreviewCallback(true);
    	orientationListener.enable();
		sensorManager.registerListener(VoiceChatActivity.this, proximitySensor, SensorManager.SENSOR_PROXIMITY);
		CameraUtil.frontCameraStartPreview();
		
		wakeLock = ((PowerManager)getSystemService(POWER_SERVICE)).newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, "VideoReceiverMainActivity");
		to = getIntent().getExtras().getString(CommandConstants.ATTR_USER_NAME);
		playAudioThread = new PlayAudioThread(SystemConstants.VOICE_PORT);
		new Thread(playAudioThread).start();
		sendAudioThread = new SendAudioThread(StateManager.getManager().getUserIP(to), SystemConstants.VOICE_PORT);
		new Thread(sendAudioThread).start();
		
		receiveExpressionThread = new ReceiveExpressionThread(SystemConstants.EXPRESSION_PORT, handler);
		new Thread(receiveExpressionThread).start();
		
		expressionBuffer = new byte[4];
		expressionSocket = null;
		
		this.initExpressionTimer();
	}
	
	public void onResume(){
		super.onResume();
		
		wakeLock.acquire();
		StateManager.getManager().setCurrentHandler(handler);
	}
	
	public void onPause(){
		super.onPause();
		wakeLock.release();
	}
	
	public void onDestroy(){
		super.onDestroy();
		
		CameraUtil.releaseFrontCamera();
		playAudioThread.stop();
		sendAudioThread.stop();
		receiveExpressionThread.stop();
		
		Document doc = null;
		if(firstTearDown){
			// send tear down request command to server
			doc = StopVoiceRequestDocGen.genDoc(StateManager.getManager().getLocalUserName(), to);
		} else {
			// send teared down command to server
			doc = StoppedVoiceChatDocGen.genDoc(StateManager.getManager().getLocalUserName(), to);
		}
		StateManager.getManager().getDataSender().add(doc);
	}
	
	private Handler handler = new Handler(){
		public void handleMessage(Message msg){
			switch(msg.what){
			case HandlerConstants.STOP_VOICE_CHAT:
				firstTearDown = false;
				showDialog(0);
				break;
			case HandlerConstants.EXPRESSION_RESULT:
				// send expression result to the other user
				String result = (String) msg.obj;
				int toSend = HandlerConstants.EXPRESSION_NULL;
				
				if(result == null || result.equals(CommonUtil.NO_FACE)){
					toSend = HandlerConstants.EXPRESSION_NULL;
				} else if(result.equals(CommonUtil.EMO_HAPPY)){
					toSend = HandlerConstants.EXPRESSION_HAPPY;
				} else if(result.equals(CommonUtil.EMO_SAD)){
					toSend = HandlerConstants.EXPRESSION_SAD;
				} else {
					toSend = HandlerConstants.EXPRESSION_NEUTRAL;
				}
				
				new Thread(new SendExpressionWorker(toSend)).start();
				break;
			case HandlerConstants.EXPRESSION_HAPPY:
				imageResult.setBackgroundResource(R.drawable.emo_happy);
				break;
			case HandlerConstants.EXPRESSION_NEUTRAL:
				imageResult.setBackgroundResource(R.drawable.emo_neutral);
				break;
			case HandlerConstants.EXPRESSION_SAD:
				imageResult.setBackgroundResource(R.drawable.emo_sad);
				break;
			case HandlerConstants.EXPRESSION_NULL:
				imageResult.setBackgroundResource(R.drawable.emo_loading);
				break;
			default:
				break;
			}
		}
	};
	
	protected Dialog onCreateDialog(int id){
		if(id == 0){
			AlertDialog.Builder builder = new AlertDialog.Builder(VoiceChatActivity.this);
			builder.setTitle(to + " has quitted, press back button to exit.");
			return builder.create();
		}
		
		return null;
	}
	
	public void setPreviewCallback(boolean flag) {
    	if (previewCallback == null) {
    		previewCallback = new PreviewCallback() {

    			@Override
    			public void onPreviewFrame(byte[] data, Camera camera) {
    				synchronized (VoiceChatActivity.this) {
    					if (chance) {
    						chance = false;
    						new PictureProcessTask(imgProcessor, handler, 0).execute(data);
    					}
    				}
    			}
    		};
    	}
    	
		CameraUtil.setFrontCameraPreviewCallback(flag ? previewCallback : null);
		
    }
	
	@Override
	public void onAccuracyChanged(Sensor arg0, int arg1) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onSensorChanged(SensorEvent arg0) {
		// TODO Auto-generated method stub
		if (arg0.sensor == proximitySensor) {
			CameraUtil.setProximity(arg0.values[0]);
		}
	}
	
	private class SendExpressionWorker implements Runnable {
		private int result;
		
		public SendExpressionWorker(int result){
			this.result = result;
		}
		
		@Override
		public void run() {
			// TODO Auto-generated method stub
			if(expressionSocket == null){
				try {
					expressionSocket = new DatagramSocket();
				} catch (SocketException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			expressionBuffer[0] = (byte) result;
			expressionBuffer[1] = (byte) (result >>> 8);
			expressionBuffer[2] = (byte) (result >>> 16);
			expressionBuffer[3] = (byte) (result >>> 24);
			
			try {
				DatagramPacket packet = new DatagramPacket(expressionBuffer, expressionBuffer.length, new InetSocketAddress(StateManager.getManager().getUserIP(to), SystemConstants.EXPRESSION_PORT));
				expressionSocket.send(packet);
			} catch (SocketException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
		
	}
}
